/** * Copyright (C) 2008-2010, Squale Project - http://www.squale.org * * This file is part of Squale. * * Squale is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or any later version. * * Squale is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Squale. If not, see <http://www.gnu.org/licenses/>. */ package org.squale.squalix.tools.ruleschecking; import java.io.File; import java.io.FilenameFilter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.tools.ant.BuildEvent; import org.apache.tools.ant.BuildListener; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.Java; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Commandline.Argument; import org.squale.squalix.core.exception.ConfigurationException; /** * Processus checkstyle L'ex�cution de l'outil Checkstyle se fait par l'interm�diaire de cette classe. Elle ex�cute * checkstyle dans une t�che ant de type java pour permettre l'acc�s aux jars sp�cifique de checkstyle qui sont en * conflit avec ceux de hibernate. Le processus prend en entr�e le fichier de configuration au format xml ainsi que la * liste des r�pertoires contenant les fichiers � analyser. Il fournit en sortie un fichier au format XML qui contient * les trasngressions rep�r�es */ public class CheckStyleProcess implements BuildListener { /** * Logger. */ private static final Log LOGGER = LogFactory.getLog( CheckStyleProcess.class ); /** R�pertoire des jars */ private File mJarDirectory; /** R�pertoire des rapports */ private File mReportDirectory; /** Indicateur d'erreur d'ex�cution */ private boolean mErrorOccurred; /** version des sources java */ private String mJavaVersion; /** * Constructeur * * @param pJarDirectory r�pertoire des jars * @param pReportDirectory r�pertoire des rapports * @param pJavaVersion la version des sources * @throws ConfigurationException si erreur */ public CheckStyleProcess( File pJarDirectory, File pReportDirectory, String pJavaVersion ) throws ConfigurationException { checkDirectory( pJarDirectory ); mJarDirectory = pJarDirectory; checkDirectory( pReportDirectory ); mReportDirectory = pReportDirectory; mJavaVersion = pJavaVersion; } /** * V�rification d'un r�pertoire * * @param pDirectory r�pertoire * @throws ConfigurationException si r�pertoire inexistant */ private void checkDirectory( File pDirectory ) throws ConfigurationException { if ( !pDirectory.exists() || !pDirectory.isDirectory() ) { // On essaye de le cr�er sinon on retourne une exception if ( !pDirectory.mkdirs() ) { throw new ConfigurationException( RulesCheckingMessages.getString( "error.bad_directory", pDirectory ) ); } } } /** * Analyse des sources avec Checkstyle * * @param pRuleFile fichier de r�gles * @param sourceDir r�pertoires contenant les sources * @param pReportName nom du rapport g�n�r� * @return fichier g�n�r� */ public File analyseSources( File pRuleFile, File sourceDir, String pReportName ) { File result = new File( mReportDirectory, pReportName ); Java task = createAntTask( pRuleFile, sourceDir, result ); mErrorOccurred = false; task.getCommandLine(); task.execute(); // mErrorOccured peut passer � true return result; } /** * Indique si une erreur s'est produite * * @return true si une erreur s'est produite */ public boolean hasErrorOccurred() { return mErrorOccurred; } /** * Create a ajava ant task for launch checkstyle * * @param pRuleFile The rule file * @param sourceDir The directory in which there is the sources to analyze * @param pResultFile The result file * @return a configured ANT task */ private Java createAntTask( File pRuleFile, File sourceDir, File pResultFile ) { // We create a java ant task Java task = new Java(); // We create the project Project antProject = new Project(); antProject.addBuildListener( this ); task.setProject( antProject ); // We fork to avoid classpath problems task.setFork( true ); // The class to call task.setClassname( "com.puppycrawl.tools.checkstyle.Main" ); // Classpath creation Path path = createClassPath( antProject ); task.setClasspath( path ); // Jvm argument. We increase the memory allocate to the JVM Argument jvmArg = task.createJvmarg(); jvmArg.setValue( "-Xmx128M" ); jvmArg = task.createJvmarg(); jvmArg.setValue( "-Xss1M" ); // We create the task argument Argument arg = task.createArg(); // The result format : xml arg = task.createArg(); arg.setValue( "-f" ); arg = task.createArg(); arg.setValue( "xml" ); // Location for the result file arg = task.createArg(); arg.setValue( "-o" ); arg = task.createArg(); arg.setValue( pResultFile.getAbsolutePath() ); // Location of the result file arg = task.createArg(); arg.setValue( "-c" ); arg = task.createArg(); arg.setValue( pRuleFile.getAbsolutePath() ); // Location of the directori in which there ise the file to analyze arg = task.createArg(); arg.setValue( "-r" ); arg = task.createArg(); arg.setValue( sourceDir.getAbsolutePath() ); return task; } /** * This method create the classpath for the java ant task that will launch checkstyle. * * @param pAntProject The ANT project for which we create the classpath * @return The correct classpath for the ant task */ private Path createClassPath( Project pAntProject ) { Path path = new Path( pAntProject ); // We create a list of all the jar of squalix and we keep only those needed for run checkstyle File[] jarFiles = mJarDirectory.listFiles( new FilenameFilter() { public boolean accept( File dir, String name ) { return name.endsWith( ".jar" ) && ( name.startsWith( "checkstyle" ) || name.startsWith( "antlr" ) || name.startsWith( "commons-beanutils" ) || name.startsWith( "commons-collections" ) || name.startsWith( "commons-logging" ) || name.startsWith( "commons-cli" ) ); } } ); // We add the list of jar to the path for ( int i = 0; i < jarFiles.length; i++ ) { path.setPath( jarFiles[i].getAbsolutePath() ); } return path; } /** * (non-Javadoc) * * @see org.apache.tools.ant.BuildListener#buildStarted(org.apache.tools.ant.BuildEvent) */ public void buildStarted( BuildEvent event ) { log( event ); } /** * (non-Javadoc) * * @see org.apache.tools.ant.BuildListener#buildFinished(org.apache.tools.ant.BuildEvent) */ public void buildFinished( BuildEvent event ) { log( event ); } /** * (non-Javadoc) * * @see org.apache.tools.ant.BuildListener#targetStarted(org.apache.tools.ant.BuildEvent) */ public void targetStarted( BuildEvent event ) { log( event ); } /** * (non-Javadoc) * * @see org.apache.tools.ant.BuildListener#targetFinished(org.apache.tools.ant.BuildEvent) */ public void targetFinished( BuildEvent event ) { log( event ); } /** * (non-Javadoc) * * @see org.apache.tools.ant.BuildListener#taskStarted(org.apache.tools.ant.BuildEvent) */ public void taskStarted( BuildEvent event ) { log( event ); } /** * (non-Javadoc) * * @see org.apache.tools.ant.BuildListener#taskFinished(org.apache.tools.ant.BuildEvent) */ public void taskFinished( BuildEvent event ) { log( event ); } /** * (non-Javadoc) * * @see org.apache.tools.ant.BuildListener#messageLogged(org.apache.tools.ant.BuildEvent) */ public void messageLogged( BuildEvent event ) { log( event ); } /** * @param pEvent �v�nement */ private void log( BuildEvent pEvent ) { // On adapte les logs en fonction de la gravit� du log initial String message = pEvent.getMessage(); Throwable exception = pEvent.getException(); // Utilisation d'un switch car on ne peut pas // se passer du mapping entre en entier et une m�thode // � appeler : on pourrait m�moriser dans une map // la m�thode et l'entier mais cel� est un peu lourd switch ( pEvent.getPriority() ) { case Project.MSG_ERR: LOGGER.error( message, exception ); mErrorOccurred = true; break; case Project.MSG_WARN: LOGGER.warn( message, exception ); break; case Project.MSG_INFO: LOGGER.info( message, exception ); break; case Project.MSG_VERBOSE: LOGGER.trace( message, exception ); break; case Project.MSG_DEBUG: LOGGER.debug( message, exception ); break; default: // Par d�faut on log sur le flux de warning LOGGER.warn( message, exception ); // par d�faut break; } } }